`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: James Forrest
// 
// Create Date:    22:50:08 09/12/2013 
// Design Name: 
// Module Name:    StepperMotorController 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module StepperMotorController(input             clk,
                              input             reset,
                              input             enable,
                              input       [3:0] address,
                              input      [31:0] dataIn,
                              output reg [31:0] dataOut,
                              input             write,
                              output            done,
                              output            interrupt,
                              output      [7:0] stepperPort
                              );

    // DRP ID
    parameter DRP_ID = 32'hA005001A;
                              
    // stepper motor positions
    parameter POS0 = 4'b0001;
    parameter POS1 = 4'b0011;
    parameter POS2 = 4'b0010;
    parameter POS3 = 4'b0110;
    parameter POS4 = 4'b0100;
    parameter POS5 = 4'b1100;
    parameter POS6 = 4'b1000;
    parameter POS7 = 4'b1001;

    // nothing requires waiting, or interrupting
    assign done = 1'b1;
    assign interrupt = 1'b0;

    // address 0 is the status word
    // status[0] is on/off
    // status[1] is direction
    reg [2:0] status;
    wire isOn = status[0];
    wire isBackward = status[1];
    wire isFullStep = status[2];

    // address 1 is the speed word
    // ie, how many clock cycle per step
    reg [31:0] speed;

    // create the signals for the steps, and the unused ones
    reg [3:0] steps;
    assign stepperPort = {steps, 4'b0000};

    // counter to keep track of timing
    reg [31:0] count;
    always @ (posedge clk, posedge reset)
        // reset
        if (reset) begin
            count <= 32'd0;
            status <= 3'd0; // default to off, forward, half step
            speed <= 32'hBEBC20; // (32'd12500000) default to one full cycle per second
        end
        else begin // run
            // write
            if (write & enable)
                case (address)
                    4'h0:    status <= dataIn[2:0];      // write the status bits
                    4'h1:    speed  <= dataIn;           // write the speed word
                    default: ;                           // no other write addresses
                endcase
            // read
            else
                case (address)
                    4'h0:    dataOut <= {29'd0, status}; // read out status word
                    4'h1:    dataOut <= speed;           // read out speed word
                    default: dataOut <= 32'd0;           // not implemented
                endcase

            // increment counter (timer)
            count <= count + 32'd1;

            // active and time up
            if (isOn & count >= speed) begin
                count <= 32'd0; // restart counter
                // move around
                if (isFullStep)
                    // full step
                    case (steps)
                        POS1: steps <= isBackward ? POS7 : POS3;
                        POS3: steps <= isBackward ? POS1 : POS5;
                        POS5: steps <= isBackward ? POS3 : POS7;
                        POS7: steps <= isBackward ? POS5 : POS1;
                        default: steps <= POS1;
                    endcase
                else
                    // half step
                    case (steps)
                        POS0: steps <= isBackward ? POS7 : POS1;
                        POS1: steps <= isBackward ? POS0 : POS2;
                        POS2: steps <= isBackward ? POS1 : POS3;
                        POS3: steps <= isBackward ? POS2 : POS4;
                        POS4: steps <= isBackward ? POS3 : POS5;
                        POS5: steps <= isBackward ? POS4 : POS6;
                        POS6: steps <= isBackward ? POS5 : POS7;
                        POS7: steps <= isBackward ? POS6 : POS0;
                        default: steps <= POS0;
                    endcase
            end
        end

endmodule
